package com.baidu.iit.pvm.runtime;

import com.baidu.iit.pvm.process.ActivityImpl;
import com.baidu.iit.pvm.process.ScopeImpl;
import com.baidu.iit.pvm.process.TransitionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * 单元节点的执行完毕操作
 *
 * @ThreadSafe
 *
 * Created by 卫立 on 2014/4/7.
 */
public class AtomicOperationTransitionDestroyScope implements AtomicOperation {

    private static Logger logger = LoggerFactory.getLogger(AtomicOperationTransitionDestroyScope.class);

    public boolean isAsync(InterpretableExecution execution) {
        return false;
    }


    public void execute(InterpretableExecution execution) {
        InterpretableExecution propagatingExecution = null;

        ActivityImpl activity = (ActivityImpl) execution.getActivity();
        if (activity.isScope()) {

            InterpretableExecution parentScopeInstance = null;
            if (execution.isConcurrent() && !execution.isScope()) {
                InterpretableExecution concurrentRoot = (InterpretableExecution) execution.getParent();
                parentScopeInstance = (InterpretableExecution) execution.getParent().getParent();

                List<InterpretableExecution> parentScopeInstanceExecutions = (List<InterpretableExecution>) parentScopeInstance.getExecutions();
                List<InterpretableExecution> concurrentRootExecutions = (List<InterpretableExecution>) concurrentRoot.getExecutions();

                if (parentScopeInstanceExecutions.size() == 1) {

                    parentScopeInstanceExecutions.get(0).setConcurrent(true);
                }

                concurrentRootExecutions.remove(execution);
                parentScopeInstanceExecutions.add(execution);
                execution.setParent(parentScopeInstance);
                execution.setActivity(activity);
                propagatingExecution = execution;


                if (concurrentRootExecutions.size() == 1) {
                    InterpretableExecution lastConcurrent = concurrentRootExecutions.get(0);
                    if (lastConcurrent.isScope()) {
                        lastConcurrent.setConcurrent(false);

                    } else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("合并当前的并发执行 {} 到跟节点中 {}", lastConcurrent, concurrentRoot);
                        }
                        concurrentRoot.setActivity((ActivityImpl) lastConcurrent.getActivity());
                        concurrentRoot.setActive(lastConcurrent.isActive());
                        lastConcurrent.setReplacedBy(concurrentRoot);
                        lastConcurrent.remove();
                    }
                }

            } else if (execution.isConcurrent() && execution.isScope()) {
                //把执行体从单元执行变成普通的节点执行器
                execution.destroy();
                propagatingExecution = execution;

            } else {
                propagatingExecution = (InterpretableExecution) execution.getParent();
                propagatingExecution.setActivity((ActivityImpl) execution.getActivity());
                propagatingExecution.setTransition(execution.getTransition());
                propagatingExecution.setActive(true);
                execution.destroy();
                execution.remove();
            }

        } else {
            propagatingExecution = execution;
        }

        ScopeImpl nextOuterScopeElement = activity.getParent();
        TransitionImpl transition = propagatingExecution.getTransition();
        ActivityImpl destination = transition.getDestination();

        //判断跳转方式，当目标节点不在父执行器内的时候，继续在内部跳转，否则跳转到外面
        if (transitionLeavesNextOuterScope(nextOuterScopeElement, destination)) {
            propagatingExecution.setActivity((ActivityImpl) nextOuterScopeElement);
            propagatingExecution.performOperation(TRANSITION_NOTIFY_LISTENER_END);
        } else {
            propagatingExecution.performOperation(TRANSITION_NOTIFY_LISTENER_TAKE);
        }
    }

    public boolean transitionLeavesNextOuterScope(ScopeImpl nextScopeElement, ActivityImpl destination) {
        return !nextScopeElement.contains(destination);
    }
}
